/********************************************************************************************
 * Copyright 2011, zhaosting <zhaosting@gmail.com>
 *
 * This file is part of QPcxPlugIn.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 3 of the License, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see <http://www.gnu.org/licenses/>.
 *
 *******************************************************************************************/

#include "qpcxhandler.h"

QPcxHandler::QPcxHandler()
{
}

bool QPcxHandler::canRead() const
{
    return device()->peek(3) == QByteArray("\A\5\1",3);
}

bool QPcxHandler::read(QImage *image)
{
    int i = 0 ;
    quint64 sz = device()->size();
    QDataStream out(device());
    out.setByteOrder(QDataStream::LittleEndian);

    out >> head.Manufacturer;
    if( 0x0A != head.Manufacturer)
    {
        qDebug()<< "The file is not a PCX files, error!";
        return false;
    }

    out >>head.Version>>head.Encoding>>head.BitsPerPixel;
    out	>> head.XMin>>head.YMin>>head.XMax>>head.YMax>>head.XRes>>head.YRes;

    for(i = 0 ;i < 48 ; i ++)
    {
        out >> head.Palette[i];
    }

    out >> head.Reserved ;
    out >> head.ColorPlanes;
    out >> head.BytesPerLine;
    out >> head.PaletteType;

    for(i = 0 ;i < 58 ; i ++)
    {
        out >> head.Filler[i];
    }

    quint64 nCnt = sz-sizeof(PCXFILEHEADER);
    char *pt_c = (char *) malloc(sizeof(char) * nCnt );

    nCnt=out.readRawData(pt_c,nCnt);

    unsigned int uTotalIdx=0;
    //read the data
    for(int iY = 0;iY < head.YMax+1; iY++)
    {
        for(i = 0;i < head.BytesPerLine;)
        {
            quint8 times = 0;
            unsigned char c;

            c=*(pt_c+uTotalIdx);
            uTotalIdx++;

            if( c >= 0xc0 )
            {
                times = c & 0x3f;
                c=*(pt_c+uTotalIdx);
                uTotalIdx++;

                for(int j = 0 ;j < times ;j ++)
                //重复的个数
                    data.append(c);
                i+=times;
            }else
            {
                i++;
                data.append(c);	//only you
            }
        }
    }
    //end read the data

    device()->seek(sz-769);

    quint8 tempD;
    out >> tempD;
    if(tempD !=0x0C )
    {
        qDebug()<<"Pcx Format Error,The file is not a 256 color file!";
        return false;
    }

    //read the palette of 256*3
    quint8 color_r = 0;
    quint8 color_g = 0;
    quint8 color_b = 0;
    QRgb	tmpRgb;
    for(i = 0 ;i <256 ;i ++)
    {
        out >> color_r;
        out >> color_g;
        out >> color_b;

        tmpRgb = ( color_r<<16) | (color_g<<8) | (color_b);
        //from RGB convert to AARRGGBB
        rgbtab.append(0xff000000 | tmpRgb);
    }

    free(pt_c) ;

    QImage img = QImage((uchar *)(data.data()),head.XMax+1,head.YMax+1,head.BytesPerLine,QImage::Format_Indexed8);
    if(img.isNull())
        qDebug() <<"Sorry ,you get a Null image.";
    QImage im;
    im = img;
    img.setColorTable(rgbtab);
    *image = img;

    return true;
}

bool QPcxHandler::write(const QImage & image)
{
    int i = 0;
    QDataStream out(device());
    out.setByteOrder(QDataStream::LittleEndian);

    head.Manufacturer = 0x0A;   //default
    head.Version = 0x05;        //default
    head.Encoding = 0x01;       //default
    head.BitsPerPixel = image.depth();       //for 256-color,etc..
    head.XMin = 0x00;
    head.XMax = image.width()-1;
    head.YMin = 0x00;
    head.YMin = image.height()-1;
    head.XRes = image.width();
    head.YRes = image.height();
    if(image.colorTable().size())
    {//for 256-color is enabled,other is disabled
        for(i = 0 ;i < 48 ; i ++)
        {
            head.Palette[i] = image.colorTable().at(i);
        }
    }else
    {
        for(i = 0 ;i < 48 ; i ++)
        {
            head.Palette[i] = 0;
        }
    }

    head.Reserved = 0x00;

    //for true-color it is 3,and other is 1,like 256-color,gray,white-black
    head.ColorPlanes = 1;

    head.BytesPerLine = image.bytesPerLine();

    //for gray pic it is 1,other is 2
    head.PaletteType = 1;

    //fill Filter
    for(i = 0 ;i < 58 ; i ++)
    {
        head.Filler[i] = 0;
    }

    /*
    quint64 nCnt = sz-sizeof(PCXFILEHEADER);
    char *pt_c = (char *) malloc(sizeof(char) * nCnt );

    nCnt=out.readRawData(pt_c,nCnt);

    unsigned int uTotalIdx=0;
    //read the data
    for(int iY = 0;iY < head.YMax+1; iY++)
    {
        for(i = 0;i < head.BytesPerLine;)
        {
            quint8 times = 0;
            unsigned char c;

            c=*(pt_c+uTotalIdx);
            uTotalIdx++;

            if( c >= 0xc0 )
            {
                times = c & 0x3f;
                c=*(pt_c+uTotalIdx);
                uTotalIdx++;

                for(int j = 0 ;j < times ;j ++)
                //重复的个数
                    data.append(c);
                i+=times;
            }else
            {
                i++;
                data.append(c);	//only you
            }
        }
    }
    //end read the data

    device()->seek(sz-769);

    quint8 tempD;
    out >> tempD;
    if(tempD !=0x0C )
    {
        qDebug()<<"Pcx Format Error,The file is not a 256 color file!";
        return false;
    }

    //read the palette of 256*3
    quint8 color_r = 0;
    quint8 color_g = 0;
    quint8 color_b = 0;
    QRgb	tmpRgb;
    for(i = 0 ;i <256 ;i ++)
    {
        out >> color_r;
        out >> color_g;
        out >> color_b;

        tmpRgb = ( color_r<<16) | (color_g<<8) | (color_b);
        //from RGB convert to AARRGGBB
        rgbtab.append(0xff000000 | tmpRgb);
    }

    free(pt_c) ;

    QImage img = QImage((uchar *)(data.data()),head.XMax+1,head.YMax+1,head.BytesPerLine,QImage::Format_Indexed8);
    if(img.isNull())
        qDebug() <<"Sorry ,you get a Null image.";
    QImage im;
    im = img;
    img.setColorTable(rgbtab);
    *image = img;
    */

    return true;
}
